PIC18 USB温度計



  Microchip社から無償で配布されている MCHPFSUSB(マイクロチップ・フルスピード・USB)から、文字通信(CDC)クラスの雛形ソフト USB Device - CDC - Basic Demo を改造して、目的のプログラムを作成することにする。これらのプログラムは 多くの機種に対応できるよう汎用性を持たせて作られているので、特定の用途には無駄な部分が多いので できるだけ削除して、フラッシュメモリ(ROM)の容量を軽減する。削除に手間がかかるが、最初から新しくプログラムを作るよりは効率的なので、このようにした。 ただし、自前で作ったプログラムに比べ、プログラムのサイズがかなり大きくなる問題がある。


  (1) USB Device - CDC - Basic Demo の整備: ( 注) MCHPFSUSB 2010_02_09 版の r14K50eb から CDC-BASIC-DEMO を使用、最新バージョンではプログラムの変更要)


  電源をパソコンのUSBから取る、コンパクトな USB温度計を作製する。
  この USB通信で用いているのは、パソコンからの受信(キーボード入力により制御)、パソコンへの送信(温度データ出力表示)であり、それぞれ 関数 getsUSBUSART、 putUSBUSART などを用いた。 特に、USB通信は、個別にデータを送・受信するのではなく、64バイト(あるいはそれ以上)以内のバイトサイズのデータをまとめて扱う。 そのため、シリアル通信やLCDの表示のように 個別の関数を続けて使用することはできず、あらかじめ 送・受信バッファにすべてのデータを組み込む必要がある。 また、パソコン側から見て、USB接続しているこれらのデータはシリアルとして扱われる。(仮想シリアルCOM3ポートが作られている(前節参照))

  まず、下図の手順により、(無駄な部分もあるが、)プロジェクトのフォルダ、ディレクトリ、#include などの整備を行なう。 無事、ビルドができたら、次に、USB Device - CDC - Basic の説明文や、他の機種の記述の部分、また、機能と関係の無い LEDを光らせる関数やボタンの関数などの削除を行なう。(ベクトル・割込み設定の部分は残す) 削除毎にビルドし、エラーが出ないことを確認する。

  


  (2) 温度計ハードの作製:


  今回は、リファレンスICによる外部参照電圧を作り 精度を上げるようにした。また、温度センサの後にオペアンプを入れ、増幅と共に 入力電圧を調整できるようにした。

  LM35DZは 価格の割りに良くできたICで、0−100℃の範囲で、高精度(±1℃)の 摂氏温度に比例する電圧を、しかも直示できるようにmV単位で出力する。( ex)50℃: 500mV) この出力電圧を、入力段のオペアンプと PIC内の演算により トータル 30倍に増幅し、ADコンバーターの参照電圧を 3.072Vとすると、出力結果を演算して5桁の作業領域のバッファに入れた値 buf[ i ] ( i = 0〜4) のうち、 buf[1] 〜 buf[3] の数字を並べて ○○.○(℃)として表示することができる。 99.9℃まで表示できるように、オペアンプのゲインは 約3倍、PIC内の倍率は 10倍 (v = v*10)とした。
  そのために、可変リファレンスIC(TL431)から出力される参照電圧が、 30 × 1024 = 30720 (10ビットADコンバーターなので 210 = 1024個に参照電圧を分割する) すなわち、 VREF+ = 3.072V となるように 10kΩVR(多回転)で調整する。

  オペアンプのゲイン(50kΩVR(多回転))は、実際に温度を測定しながら最後に調整する。(* もっと直線性の良い回路で作製し、また、さらに精度の高いリファレンスICも必要に応じて用いていきたい。)

 


  (3) プログラムの作成:


  プログラムで特に作製する部分は、main と processIO と 初期化の部分である。

  12MHz外部振動子(レゾネータ)による発振を用いる。 CPUデバイダの値は1/1(NOCLKDIV、 CLKDIV2では 1/2、4では1/4)とし、48MHz → 12MHzの動作クロックとなる。Delay はこれにあわせて設定。 USBは 48MHz発振でパソコンと通信できる。 (↓1列目)

  割込み関数部はDEMOプログラムに設定済みで、USBの ポーリングモード設定(USBDeviceTasks();)がすでに高優先割り込みの中に入っている。そのため、なぜか、タイマーなどの割込みが 低優先割込みにさえも 一切使えず(使うとUSB通信に変調をきたして、パソコンが受け付けない)、やむなく 時間設定は Delay で行うしかなかった。 (↓ 2列目)

  OpenADCの2項目の設定(ADコンバーターの参照電圧)で、VREF+(外部参照電圧・+・ポジ)と GNDとの間の電圧をとった。 また、動作周波数にあわせて、ADC_FOSCを16に変更した。 (main関数、↓3列目)


  main関数から飛ぶ 関数ProcessIOで、CDCクラスの送受信を行なう。 (↓4列目)

  ・ getsUSBUSART(受信バッファ名(USB_OUT_Buffer)、文字数(64)) ・・・ (64バイトの)文字データをパソコンから受信し、受信バッファ(USB_OUT_Buffer)に格納し、含まれているバイト数を読み込む

  ・ mUSBUSARTIsTxTrfReady() ・・・ これが1ならば USB送信可能、送信のとき必ず if 文でチェックする(ポーリング処理なので While文は不可)

  ・ putUSBUSART(送信バッファ名(USB_IN_Buffer)、文字数(5) ・・・ 送信バッファ(USB_IN_Buffer)に格納されている (5バイトの)文字データを 送信にセットする(* 書き込むバイト数が64バイトを超えている場合、64バイト単位で複数回に分けて送信する) また、
        ・ putrsUSBUSART(”文字列”) ・・・ プログラム(ROM)に書かれている文字列データをそのまま送る
        ・ putsUSBUSART(”文字列”) ・・・ ユーザーデータ(RAM)にある文字列データをそのまま送る

  ・ CDCTxService() ・・・ 実際に送信を行なう

  送信のときの使い方は、いずれも、
      if(mUSBUSARTIsTxTrfReady()){
      putUSBUSART(buffer, WriteSize);
      }
      CDCTxService();
のように前後で挟む書式になる。送る文字数を間違えると バッファのゴミが表示されるので注意。

  バッファに入る文字データの書き方は、0x××、の他に、 '(数字・アルファベト)' でも良い。( ex) switch文の case '1': ) switch文は、 switch - case: (〜の場合)-break, case: - break, ・・・ default:(その他の場合) - break の形で、いくつもあるジョブを場合分けする分岐命令に用いられる。





   ● ソース(main.cのみ):      ● lib_adc.h 


  (4) 動作チェック と 問題点:


  このプログラムで動かしてみたところ、USBケーブルを差し込むと、LCDに温度表示が現われる。 USBケーブルが差し込まれている状態で、TeraTerm などのシリアル受信ソフトを起動すると、パソコンのキーボードの Enterキー (パソコンから受信したキーコード: 0x0A)を押すたびに、10秒間隔で 温度が縦1列に表示され続け、また、表示の更新が停止する。
  消費電流は10mA前後で、USBからの+5V電源容量は最大100mA(パソコンによっては500mA)なので、充分余裕がある。(電源系統のショートには要注意)




  USB Device - CDC - Basic Demo を改造して用いる際の問題点は、2つあり、

  1つ目は、リンクが複雑なままのプログラム使用で プログラムのサイズが大きくなることである。 hex ファイルのファイルサイズを確認したところ、25kバイトにもなり、さらに2個以上のADコンバーターを動かすと、ROMへの書き込みはできても、RAMの容量がオーバーして動作が止まってしまうことがあった。(hex ファイルは、LCDのみ使用の別プログラムで 6−8kバイト、LCD無しのUSB使用で 20kバイト) USB内蔵マイコンとして改造プログラムで使うには、同様に使えて 容量が大きい、もう1ランク上の PIC18F2550 等を用いるべきと思われる。 因みに、使用したMPLAB C18は、最適化の期限が過ぎている。

  2つ目は、USB Device - CDC - Basic Demo には、USBのポーリングやタスク命令が ソースプログラムの高優先割り込みに初めから組み込まれているため、このままでは タイマー機能も、割り込み機能もほとんど使えないことである。 (特に、タイマー1との相性が悪い。ベクタを 0x08、0x18 以外に設定しても同じ) 同じようなプログラムで タイマー0(16ビット)の割込みを低優先で入れている成功例もあるので、タイマを全く使用しないか、あるいは、リンクしている USB関数群の通信処理部分の前後に割り込みを禁止・再開する記述を追加する必要があると思われる。





   §  デジタルからアナログへ     ・・・ アナログ放送は終了したけれど。。


  マイコンの分野で”アナログ”といえば、ADコンバーター入力や コンパレータ入力のことを言いますが、電子工学一般では、オーディオ、高周波、オペアンプなどを アナログ回路と呼びます。
  マイコンでは、細かく変化する多くの信号でサイン波を表現したり、ADコンバータで電圧レベルを細かく区切るなど、デジタル”擬似的なアナログ信号”を作るのが一般的です。

  さて、論理学・数学的には、デジタル、アナログとはどういうことを意味するのでしょう? まずは、振動方向が 1 か 0 (あるいは、+1 か −1)しかない、デジタルの世界を考えましょう。
  ゲーデルの不完全性定理は、自然数論を含む公理系において、「その公理系が無矛盾ならば、その公理系で 証明も反証もできない命題が存在する」、というものです。それは、自然数を扱い、しかも、代入可能な論理系であれば、論理学、数学に限らず、(階層構造を持つ)言語や、デジタル回路、コンピューターのプログラム(関数)にも成り立ちます。

  デジタル回路では、たとえば NOTゲートを奇数個つなげて 最後のゲート出力を初めのゲート入力に帰還すれば、全体が”矛盾”に陥って、発振します。これは 回路が 「負帰還」の状態になっているからです。(TTL ICの NOTgate(74LS04)で実験したところ、11個つなげて 10数MHzで発振)

  プログラムでは、「無限ループ」がよく知られています。 C言語では、 メインプログラムで while(1) を1箇所だけ入れて、ほとんどすべてのプログラムに用いられますが、これは、マイコンの設定や初期化の後”電源を切るまで、while(1){ } の内容を 無限に繰り返す”、という論理構造です。 プログラムのどこかで、これとは別の無限ループに陥ると すべての動作が止まってしまい大変困りますが、電源を切るまで 装置としてある一定の動作を繰り返し行なうためには、通常、一つのプログラムに1個だけ用いられます。 割込み関数や 他の関数、ヘッダファイルへ飛ぶことがあっても 再びそこに戻るので、基本構造は同じです。

      言語               数学     プログラム      デジタル回路   
 担体    階層構造をもつ言語     自然数を含む帰納的な関数   アルゴリズム  NAND回路の組合せ 
 方法 自己・相互を否定的に言及 それ自身のゲーデル数をもとの式に代入  ジャンプ・ループ     負帰還回路
 結果    パラドックス(矛盾)   不完全性(証明も反証もできない)   無限ループ   不定状態・発振

  では、アナログ回路では、この「矛盾」とは どのような形態を持っているのでしょうか?


  デジタルでは、+1 と −1 の2つの状態のみが許されましたが、アナログでは その中間の値 iθ が存在します。(+1 と −1 の中間の値は 0 ではない!) 矛盾して、発振した状態が、きれいな正弦波のような形態になります。 デジタルは、このアナログの 特殊な状態(θ = π+2nπ、または、 −π+2nπ、 n = 0、±1、±2、・・・)の一つです。
  電磁気学では、虚数単位 i の導入は便宜的なものですが、量子力学では 本質的に、物理量が複素数となっています。 驚くべきことに、自然の本質は 「複素数」です。

  この iθ の特殊な場合、オイラーの恒等式として知られる iπ = −1 は、数学上 最もエレガントな式といわれています。 それは、全く独立して成立した 幾何学、代数学、解析学 という 数学の3大分野における、それぞれの 数学定数 π、 i 、 e が、この式において 1つに合体しているからです。

  このように、思索(=数学)においても、自然(=量子力学)においても、 3つの最も根本的な要素が 1つに合体、すなわち、「三位一体」になっています。



  思索も 自然も、 天地万物を創造した神 が、「三位一体の神」、すなわち、「キリスト」であることを あかししています。


    (参考)  →  コンピューターと 神、      不完全性定理の証明、    神の愛の奥義



               戻る          トップへ戻る